package com.demo.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.demo.chain.FxSqlCheckChain;
import com.demo.chain.PreExecuteChain;
import com.demo.chain.ResultProcessChain;
import net.hasor.core.ApiBinder;
import net.hasor.core.DimModule;
import net.hasor.core.TypeSupplier;
import net.hasor.dataql.Finder;
import net.hasor.dataql.QueryApiBinder;
import net.hasor.dataql.fx.db.FxSqlCheckChainSpi;
import net.hasor.dataway.spi.PreExecuteChainSpi;
import net.hasor.dataway.spi.ResultProcessChainSpi;
import net.hasor.db.JdbcModule;
import net.hasor.db.Level;
import net.hasor.spring.SpringModule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;


/**
 * @Classname DatawayModule
 * @Description 将Hasor模块注入spring，并注入数据源
 * @Date 2023/7/28 11:43
 * @Created by Leo825
 */
@DimModule  // Hasor 中的标签，表明是一个Hasor的model
@Component  // Spring 中的标签，表明是一个组件
public class DatawayModule implements SpringModule,TypeSupplier {
    // 默认数据源
    @Autowired
    private DataSource dataSource;
    // 数据源1的配置信息
    @Value("${spring.datasource.db1.url}")
    private String jdbcUrl1;
    @Value("${spring.datasource.db1.driver-class-name}")
    private String driver1;
    @Value("${spring.datasource.db1.username}")
    private String username1;
    @Value("${spring.datasource.db1.password}")
    private String password1;

    // 数据源2的配置信息
    @Value("${spring.datasource.db2.url}")
    private String jdbcUrl2;
    @Value("${spring.datasource.db2.driver-class-name}")
    private String driver2;
    @Value("${spring.datasource.db2.username}")
    private String username2;
    @Value("${spring.datasource.db2.password}")
    private String password2;

    @Resource
    private ApplicationContext applicationContext;

    @Override
    public <T> T get(Class<? extends T> targetType) {
        return applicationContext.getBean(targetType);
    }

    @Override
    public <T> boolean test(Class<? extends T> targetType) {
        return applicationContext.getBeanNamesForType(targetType).length > 0;
    }

    @Override
    public void loadModule(ApiBinder apiBinder) throws Throwable {
        // .DataSource form Spring boot into Hasor
        apiBinder.installModule(new JdbcModule(Level.Full, this.dataSource));
        // 注入数据源
        apiBinder.installModule(new JdbcModule(Level.Full, this.dataSource));
        apiBinder.installModule(new JdbcModule(Level.Full, "dataSource1", getDataSource(jdbcUrl1, driver1, username1, password1)));
        apiBinder.installModule(new JdbcModule(Level.Full, "dataSource2", getDataSource(jdbcUrl2, driver2, username2, password2)));

        // 打印sql日志
        apiBinder.bindSpiListener(FxSqlCheckChainSpi.class, FxSqlCheckChain.getInstance());
        // 数据权限参数
        apiBinder.bindSpiListener(PreExecuteChainSpi.class, PreExecuteChain.getInstance());
        // 返回结果
        apiBinder.bindSpiListener(ResultProcessChainSpi.class, ResultProcessChain.getInstance());
//        // 登录过滤
//        apiBinder.bindSpiListener(LoginPerformChainSpi.class, LoginPerformChain.getInstance());
        // 登录 token 过滤
//        apiBinder.bindSpiListener(LoginTokenChainSpi.class, LoginTokenChain.getInstance());

        // udf/udfSource/import 指令 的类型创建委托给 spring
        QueryApiBinder queryBinder = apiBinder.tryCast(QueryApiBinder.class);
        queryBinder.bindFinder(Finder.TYPE_SUPPLIER.apply(this));
    }


    /**
     * 注入数据源
     *
     * @param
     * @param driver
     * @param username
     * @param password
     * @return
     */
    private DruidDataSource getDataSource(String jdbcUrl, String driver, String username, String password) {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(jdbcUrl);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driver);
        // 用来检测连接是否有效
        dataSource.setValidationQuery("SELECT 1");
        // 借用连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能
        dataSource.setTestOnBorrow(false);
        // 归还连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能
        dataSource.setTestOnReturn(false);
        // 连接空闲时检测，如果连接空闲时间大于timeBetweenEvictionRunsMillis指定的毫秒，
        // 执行validationQuery指定的SQL来检测连接是否有效
        // 如果检测失败，则连接将被从池中去除
        dataSource.setTestWhileIdle(true);
        dataSource.setTimeBetweenEvictionRunsMillis(60000);//1分钟
        dataSource.setMaxActive(20);
        dataSource.setInitialSize(5);
        return dataSource;
    }
}
